package com.gitee.wsl.prism4j

import com.gitee.wsl.prism4j.languages.*

class MyGrammarLocator : GrammarLocator {
    private val cache: MutableMap<String, Prism4j.Grammar> = HashMap(3)

    private val pluginGrammarMap = mutableMapOf<String, (Prism4j) -> Prism4j.Grammar>()

    fun regeditGrammar(name:String, block:(Prism4j) -> Prism4j.Grammar){
        pluginGrammarMap[name] = block
    }

    override fun grammar(prism4j: Prism4j, language: String): Prism4j.Grammar? {
        val name = realLanguageName(language)
        var grammar = cache[name]
        if (grammar != null) {
            if (NULL == grammar) {
                grammar = null
            }
            return grammar
        }
        grammar = obtainGrammar(prism4j, name)
        if (grammar == null) {
            cache[name] = NULL
        } else {
            cache[name] = grammar
            triggerModify(prism4j, name)
        }
        return grammar
    }

    protected fun realLanguageName(name: String): String {
        return when (name) {
            "js" -> "javascript"
            "xml", "html", "mathml", "svg" -> "markup"
            "dotnet" -> "csharp"
            "jsonp" -> "json"
            else -> name
        }
    }

    protected fun obtainGrammar(prism4j: Prism4j, name: String): Prism4j.Grammar? {
        pluginGrammarMap[name]?.let {
            return it.invoke(prism4j)
        }
        return when (name) {
            "brainfuck" -> Prism_brainfuck.create(prism4j)
            "c" -> Prism_c.create(prism4j)
            "clike" -> Prism_clike.create(prism4j)
            "clojure" -> Prism_clojure.create(prism4j)
            "cpp" -> Prism_cpp.create(prism4j)
            "csharp" -> Prism_csharp.create(prism4j)
            "css" -> Prism_css.create(prism4j)
            "css-extras" -> Prism_css_extras.create(prism4j)
            "dart" -> Prism_dart.create(prism4j)
            "git" -> Prism_git.create(prism4j)
            "go" -> Prism_go.create(prism4j)
            "groovy" -> Prism_groovy.create(prism4j)
            "java" -> Prism_java.create(prism4j)
            "javascript" -> Prism_javascript.create(prism4j)
            "json" -> Prism_json.create(prism4j)
            "latex" -> Prism_latex.create(prism4j)
            "makefile" -> Prism_makefile.create(prism4j)
            "markdown" -> Prism_markdown.create(prism4j)
            "markup" -> Prism_markup.create(prism4j)
            "python" -> Prism_python.create(prism4j)
            "scala" -> Prism_scala.create(prism4j)
            "sql" -> Prism_sql.create(prism4j)
            "swift" -> Prism_swift.create(prism4j)
            "yaml" -> Prism_yaml.create(prism4j)
            "kotlin" -> Prism_kotlin.create(prism4j)
            "lua" -> Prism_lua.create(prism4j)
            else -> NULL
        }
    }

    protected fun triggerModify(prism4j: Prism4j, name: String) {
        when (name) {
            "markup" -> {
                prism4j.grammar("css")
                prism4j.grammar("javascript")
            }
            "css" -> prism4j.grammar("css-extras")
        }
    }

    override fun languages(): Set<String> {
        val set = mutableSetOf<String>()

        set.addAll(pluginGrammarMap.keys)
        set.add("brainfuck")
        set.add("c")
        set.add("clike")
        set.add("clojure")
        set.add("cpp")
        set.add("csharp")
        set.add("css")
        set.add("css-extras")
        set.add("dart")
        set.add("git")
        set.add("go")
        set.add("groovy")
        set.add("java")
        set.add("javascript")
        set.add("json")
        set.add("kotlin")
        set.add("latex")
        set.add("makefile")
        set.add("markdown")
        set.add("markup")
        set.add("python")
        set.add("scala")
        set.add("sql")
        set.add("swift")
        set.add("yaml")
        set.add("lua")
        return set
    }

    companion object {
        private val NULL: Prism4j.Grammar = object : Prism4j.Grammar {
            override fun name(): String {
                return ""
            }

            override fun tokens(): MutableList<Prism4j.Token> {
                return mutableListOf()
            }
        }
    }
}